#pragma once
#include<iostream>
#include<vector>
#include<queue>
#include<pthread.h>
#include"Thread.hpp"
#include"LockGuard.hpp"
#include"Log.hpp"

using namespace ThreadModule;
const static int gdefayltthreadnum = 10;

template<typename T>
class ThreadPool
{
    private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);//上锁
    }
    void UnlockQueue()
    {
        pthread_mutex_unlock(&_mutex);//解锁
    }
    void ThreadSleep() //等待
    {
        pthread_cond_wait(&_cond,&_mutex);
    }
    void ThreadWakeup()//唤醒
    {
        pthread_cond_signal(&_cond);
    }
    void ThreadWakeupAll()//唤醒所有
    {
        pthread_cond_broadcast(&_cond);
    }
    ThreadPool(int threadnum = gdefayltthreadnum)
        :_threadnum(threadnum)
        ,_waitnum(0)
        ,_isrunning(false)
    {

        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
        LOG(INFO,"ThreadPool Construct()");
    }
    void InitThreadpool()//初始化线程池
    {
        //指向构建出所有的线程，不启动
        for(int num = 0;num<_threadnum;num++)
        {
            std::string name = "thread-"+std::to_string(num+1);
            _threads.emplace_back(std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1),name);
            LOG(INFO,"init thread %s done",name.c_str());
        }
    }
    void Start()//创建
    {
        for(auto &thread:_threads)
        {
            thread.Start();
        }
    }
    void HandlerTask(std::string name)//处理任务
    {
        LOG(INFO,"%s is running...",name.c_str());
        while (true)
        {
            //1:保证队列安全
            LockQueue();
            //2:队列中不一定有数据
            while (_task_queue.empty()&&_isrunning)
            {
                _waitnum++;
                ThreadSleep();
                _waitnum--;
            }
            //判断线程池是否退出&&队列为空
            if(_task_queue.empty()&&!_isrunning)
            {
                UnlockQueue();//解锁
                break;
            }
            //如果线程池不退出&&任务队列不是空的
            //如果线程池为已经退出，任务队列不为空--处理完所有任务，然后退出
            //肯定有任务，处理任务
            T t = _task_queue.front();
            _task_queue.pop();
            UnlockQueue();
            LOG(DEBUG,"%s get atask",name.c_str());
            
            t();
            LOG(DEBUG,"%s handler a task, result is %s",name.c_str(),t.ResultToString().c_str());
        }
    }
 //禁止复制拷贝
 ThreadPool<T> &operator = (const ThreadPool<T> &) = delete;
 ThreadPool(const ThreadPool<T> &) = delete;
    public:
        static ThreadPool<T> *Getinstance()
        {
                //如果多线程获取线程池对象下面的代码就出现问题了
                //只有第一次会创建对象，后续是获取；
                //两次的判断方式，可以有效减少索取单例的加锁成本，而且保证线程安全；
                if(nullptr == _instance)
                {
                    LockGuard lockguard(&_lock);
                    if(nullptr == _instance)
                    {
                        _instance = new ThreadPool<T>();
                        _instance->InitThreadpool();
                        _instance->Start();
                        LOG(DEBUG,"创建线程单例");
                        return _instance;
                    }
                }
                LOG(DEBUG,"获取线程单例");
                return _instance;
        }
        void Stop()
        {
            LockQueue();
            _isrunning = false;
            ThreadWakeupAll();
            UnlockQueue();
        }
        void Wait()
        {
            for(auto &thread: _threads)
            {
                thread.Join();
                LOG(INFO,"%s is quit...",thread.name().c_str());
            }
        }
        bool Enqueue(const T &t)
        {
            bool ret = false;
            LockQueue();
            if(_isrunning)
            {
                _task_queue.push(t);
                if(_waitnum>0)
                {
                    ThreadWakeup();
                }
                LOG(DEBUG,"enqueue task success");
                ret = true;
            }
            UnlockQueue();
            return ret;
        }
        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }
    private:
    int _threadnum;
    std::vector<Thread> _threads;
    std::queue<T> _task_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    int _waitnum;
    int _isrunning;
//添加单例模式
    static ThreadPool<T> *_instance;
    static pthread_mutex_t _lock;
    
};
template<typename T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

template<typename T>
pthread_mutex_t ThreadPool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;